/**
 * Copyright (C), 2020-2021,贵州铭明网络科技有限公司
 * FileName: WxPayV2Util
 * Author:   杨朝湖
 * Date:     2021/3/10 15:58
 * Description:
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.gym.util.v2;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.gym.util.base.PayV2;
import com.gym.util.pojo.v2.only.close.CloseOrderBo;
import com.gym.util.pojo.v2.only.placeorder.PlaceOrderBo;
import com.gym.util.pojo.v2.only.placeorder.SceneInfo;
import com.gym.util.pojo.v2.only.refund.RefundOrderBo;
import com.gym.util.pojo.v2.only.refund.select.SelectRefundOrderBo;
import com.gym.util.pojo.v2.only.select.SelectOrderBo;
import com.gym.util.pojo.v3.only.vo.initiatepayment.WxPayResult;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;


/**
 * 〈一句话功能简述〉<br>
 * 〈〉
 *
 * @author Gym
 * @create 2021/3/10
 * @since 1.0.0
 */
public class WxPayV2Util extends PayV2 {

    private static final String url_prex = "https://api.mch.weixin.qq.com/";

    /**
     * 除付款码支付场景以外，商户系统先调用该接口在微信支付服务后台生成预支付交易单，
     * 返回正确的预支付交易会话标识后再按Native、JSAPI、APP等不同场景生成交易串调起支付。
     *
     * @param placeOrderBo 请求参数实体
     * @param sceneInfo    请求参数实体
     * @param key          ApiV2秘钥
     * @param url          请求地址
     * @return
     * @throws Exception
     */
    public static String placeOrder(PlaceOrderBo placeOrderBo, SceneInfo sceneInfo, String key, String url) throws Exception {
        String jsonStr = JSONUtil.toJsonStr(placeOrderBo);
        Map<String, String> map = JSON.parseObject(jsonStr, Map.class);
        map.put("total_fee", placeOrderBo.getTotal_fee() + "");
        if (sceneInfo != null) {
            map.put("scene_info", JSONUtil.toJsonStr(sceneInfo));
        }
        String signedXml = generateSignedXml(map, key);
        Map<String, String> stringStringMap = notCarryCertificateRequestPost(placeOrderBo.getMch_id(), url_prex + url, signedXml);
        if ("SUCCESS".equals(stringStringMap.get("return_code"))) {
            switch (placeOrderBo.getTrade_type()) {
                case "JSAPI":
                case "APP":
                    return stringStringMap.get("prepay_id");
                case "NATIVE":
                    return stringStringMap.get("code_url");
                case "MWEB":
                    return stringStringMap.get("h5_url");
                default:
                    return null;
            }
        } else {
            return stringStringMap.toString();
        }
    }

    /**
     * 微信调起支付参数
     *
     * @param prepayId 微信下单返回的prepay_id
     * @param appId    应用ID(appid)
     * @param key      ApiV2秘钥
     * @return 返回参数直接返回
     * @throws Exception
     */
    public static WxPayResult wxTuneUp(String prepayId, String appId, String key) throws Exception {
        long time = System.currentTimeMillis() / 1000;
        Map<String, String> map = new HashMap<>();
        map.put("appId", appId);
        map.put("nonceStr", time + "");
        map.put("package", "prepay_id=" + prepayId);
        map.put("signType", "HMAC-SHA256");
        map.put("timeStamp", time + "");
        String sign = generateSignature(map, key);
        WxPayResult wxPayResult = new WxPayResult(appId, time + "", time + "", "prepay_id=" + prepayId, "HMAC-SHA256", sign);
        return wxPayResult;
    }

    /**
     * 处理微信异步回调
     *
     * @param request
     * @param response
     * @param privateKey 32的秘钥
     * @return 支付的订单号
     */
    public static Map<String, String> notify(HttpServletRequest request, HttpServletResponse response, String privateKey) throws Exception {
        String result = readData(request);
        Map<String, String> stringStringMap = xmlToMap(result);
        //发送消息通知微信
        sendMessage(response, result);
        return stringStringMap;
    }

    /**
     * 查询订单信息
     *
     * @param selectOrderBo 请求参数实体
     * @param key           ApiV2秘钥
     * @return
     * @throws Exception
     */
    public static Map<String, String> selectOrder(SelectOrderBo selectOrderBo, String key) throws Exception {
        String jsonStr = JSONUtil.toJsonStr(selectOrderBo);
        Map<String, String> map = JSON.parseObject(jsonStr, Map.class);
        String signedXml = generateSignedXml(map, key);
        Map<String, String> stringStringMap = notCarryCertificateRequestPost(selectOrderBo.getMch_id(), url_prex + "pay/orderquery", signedXml);
        return stringStringMap;
    }

    /**
     * 关闭订单
     *
     * @param closeOrderBo 参数实体
     * @param key          ApiV2秘钥
     * @return
     * @throws Exception
     */
    public static Map<String, String> closeOrder(CloseOrderBo closeOrderBo, String key) throws Exception {
        String jsonStr = JSONUtil.toJsonStr(closeOrderBo);
        Map<String, String> map = JSON.parseObject(jsonStr, Map.class);
        String signedXml = generateSignedXml(map, key);
        Map<String, String> stringStringMap = notCarryCertificateRequestPost(closeOrderBo.getMch_id(), url_prex + "pay/closeorder", signedXml);
        return stringStringMap;
    }

    /**
     * 订单退款
     *
     * @param refundOrderBo 参数实体
     * @param key           ApiV2秘钥
     * @return
     * @throws Exception
     */
    public static Map<String, String> refundOrder(RefundOrderBo refundOrderBo, String key) throws Exception {
        String jsonStr = JSONUtil.toJsonStr(refundOrderBo);
        Map<String, String> map = JSON.parseObject(jsonStr, Map.class);
        String signedXml = generateSignedXml(map, key);
        Map<String, String> stringStringMap = notCarryCertificateRequestPost(refundOrderBo.getMch_id(), url_prex + "secapi/pay/refund", signedXml);
        return stringStringMap;
    }

    /**
     * 查询退款订单
     *
     * @param selectRefundOrderBo 参数实体
     * @param key                 ApiV2秘钥
     * @return
     * @throws Exception
     */
    public static Map<String, String> selectRefundOrder(SelectRefundOrderBo selectRefundOrderBo, String key) throws Exception {
        String jsonStr = JSONUtil.toJsonStr(selectRefundOrderBo);
        Map<String, String> map = JSON.parseObject(jsonStr, Map.class);
        String signedXml = generateSignedXml(map, key);
        Map<String, String> stringStringMap = notCarryCertificateRequestPost(selectRefundOrderBo.getMch_id(), url_prex + "pay/refundquery", signedXml);
        return stringStringMap;
    }

}